package camp

import (
	"github.com/pkg/errors"
	"sync/atomic"
	"unsafe"
)

type Pair interface {
	linked
	Key()string
	Hash()uint64
	SetElement(element interface{})error
	Element()interface{}
	Copy()Pair
}
type linked interface {
	Next()Pair
	SetNext(pair Pair)error
}
type pair struct {
	key string
	hash uint64
	element unsafe.Pointer
	next unsafe.Pointer

}

func (this *pair)Key()string  {
	return this.key
}
func (this *pair)Hash()uint64  {
	return this.hash
}
func (this *pair)SetElement(element interface{})error  {
	if element == nil{
		return errors.New("element is nill")
	}
	atomic.StorePointer(&this.element,unsafe.Pointer(&element))
	return  nil
}
func (this *pair)Element()interface{}  {
	pointer := atomic.LoadPointer(&this.element)
	if pointer == nil{
		return nil
	}
	return *(*interface{})(pointer)
}
func (this *pair)SetNext(next Pair)error  {
	if next == nil{
		atomic.StorePointer(&this.next,nil)
	}
	pp,ok := next.(*pair)
	if !ok {
		return errors.New("Pair type is not *pair")
	}
	atomic.StorePointer(&this.next,unsafe.Pointer(pp))
	return nil
}
func (this *pair)Next()Pair  {
	pp := atomic.LoadPointer(&this.next)
	if pp == nil{
		return nil
	}
	return (*pair)(pp)
}
func (this *pair)Copy()Pair  {
	pp,_:= New(this.Key(),this.Element())
	return pp
}
func New(key string,element interface{})(Pair,error)  {
	if element == nil{
		return nil,errors.New("element is nil")
	}
	pp := &pair{
		key:key,
		hash:hash(key),
	}
	pp.element = unsafe.Pointer(&element)
	return pp,nil
}
func hash(str string) uint64 {
	seed := uint64(13131)
	var hash uint64
	for i := 0; i < len(str); i++ {
		hash = hash*seed + uint64(str[i])
	}
	return (hash & 0x7FFFFFFFFFFFFFFF)
}